package bs.util.tool.commongui.plugins.more;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import org.mozilla.universalchardet.UniversalDetector;

import bs.util.io.PropertiesUtils;
import bs.util.tool.commongui.GuiJPanel;
import bs.util.tool.commongui.GuiUtils;
import bs.util.tool.commongui.utils.FileUtils;
import bs.util.tool.commongui.utils.SearchFileNameParams;

/**
 * 文本编码识别.
 */
public class JUniversalChardet extends GuiJPanel {

	private static final long serialVersionUID = 1L;

	/**
	 * 探测文本/文件夹路径表单.
	 */
	private JTextField detectPathTextField = new JTextField();
	/**
	 * 探测文本/文件夹路径选择.
	 */
	private JFileChooser detectPath_Chooser = new JFileChooser();

	/**
	 * 探测按钮.
	 */
	private JButton detectButton;

	/**
	 * 取样大小表单.
	 */
	private JTextField detectSizeTextField = new JTextField("4096", 7);

	/**
	* 文件名包含字符表单.
	*/
	private JTextField fileNameContainsTextField;
	/**
	 * 文件名不包含字符表单.
	 */
	private JTextField fileNameNotContainsTextField;
	/**
	 * 文件名是否支持正则.
	 */
	private boolean fileNameSupportRegex = true;

	/**
	 * 探测结果文本域.
	 */
	private JTextArea resultTextArea = createJTextArea(GuiUtils.font14_un);

	public JUniversalChardet() {

		// 主面板：边界布局，分North、Center两部分，North用于放置输入及条件控件，Center是放置探测结果输出
		setLayout(new BorderLayout());

		// 输入及条件Panel
		JPanel inputPanel = new JPanel(new GridLayout(2, 1));

		// 探测文本/文件夹表单、探测按钮Panel
		JPanel fileChooAndDetectPanel = new JPanel(new BorderLayout());
		// 探测文本/文件夹表单
		addJLabel(fileChooAndDetectPanel, "  探测文本/文件夹: ", GuiUtils.font14_cn, BorderLayout.WEST);
		JPanel fileChooPanel = new JPanel(new BorderLayout());
		fileChooPanel.add(new JPanel(), BorderLayout.NORTH);
		addJTextField(fileChooPanel, detectPathTextField, GuiUtils.font14_un, BorderLayout.CENTER);
		fileChooPanel.add(new JPanel(), BorderLayout.SOUTH);
		fileChooAndDetectPanel.add(fileChooPanel, BorderLayout.CENTER);

		JPanel buttonFlowPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
		addJButton(buttonFlowPanel, "浏览", "", GuiUtils.font12_cn,
				buttonBrowseListener(detectPath_Chooser, detectPathTextField));
		// 探测按钮
		detectButton = createJButton("探测", "", GuiUtils.font14b_cn);
		detectButton.addMouseListener(new MouseListener() {
			public void mouseReleased(MouseEvent event) {
				String path = detectPathTextField.getText().trim();
				File file = new File(path);
				if (!file.exists()) {
					showMessage("探测文本/文件夹不存在！", "警告", JOptionPane.WARNING_MESSAGE);
					return;
				}
				Map<String, Object> paramsMap = new HashMap<String, Object>();
				paramsMap.put("fileNameContainsText", fileNameContainsTextField.getText().trim());
				paramsMap.put("fileNameNotContainsText", fileNameNotContainsTextField.getText().trim());
				paramsMap.put("fileNameSupportRegex", fileNameSupportRegex);
				detectButton.setEnabled(false);

				resultTextArea.setText("");
				try {
					int detectLength = Integer.parseInt(detectSizeTextField.getText().trim());
					if (!file.isDirectory()) {
						appendDetectResult(resultTextArea, file, detectLength);
					} else {
						List<File> files = new ArrayList<File>();
						FileUtils.loopDirectory(file, files, new SearchFileNameParams(paramsMap));
						for (File fFile : files) {
							appendDetectResult(resultTextArea, fFile, detectLength);
						}
						resultTextArea.append("\nCount files: " + files.size());
					}
				} catch (NumberFormatException e) {
					showMessage("取样大小必须是正整数！", "警告", JOptionPane.WARNING_MESSAGE);
				} catch (IOException e) {
					showExceptionMessage(e);
				}
				detectButton.setEnabled(true);
			}

			public void mousePressed(MouseEvent e) {
				resultTextArea.setText("");
			}

			public void mouseExited(MouseEvent e) {
			}

			public void mouseEntered(MouseEvent e) {
			}

			public void mouseClicked(MouseEvent e) {
			}
		});
		buttonFlowPanel.add(detectButton);
		// 探测路径选择控件
		detectPath_Chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); // 可选择文件/文件夹
		fileChooAndDetectPanel.add(buttonFlowPanel, BorderLayout.EAST);
		inputPanel.add(fileChooAndDetectPanel);

		// 高级条件Panel
		JPanel advancePanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
		// 取样大小
		addJLabel(advancePanel, " ", GuiUtils.font12_cn);
		addJLabel(advancePanel, "取样大小: ", GuiUtils.font14_cn);
		addJTextField(advancePanel, detectSizeTextField, GuiUtils.font14_cn);
		addJLabel(advancePanel, "Byte", GuiUtils.font14_cn);

		// 文件名包含(不包含)字符
		String confPropsFile = "conf/JUniversalChardet/searchFiletypes.properties";
		String containsFiletypes = "";
		String notContainsFiletypes = "";
		try {
			Properties confProperties = PropertiesUtils.getProperties(GuiUtils.getActualPath(confPropsFile));
			containsFiletypes = confProperties.getProperty("ContainsFiletypes").trim();
			notContainsFiletypes = confProperties.getProperty("NotContainsFiletypes").trim();
		} catch (IOException e) {
			logLoadPropertiesException(confPropsFile, e);
		}
		addJLabel(advancePanel, " 文件名包含字符: ", GuiUtils.font14_cn);
		String fileNameContains = containsFiletypes.length() > 0 ? "\\.(" + containsFiletypes.replace(",", "|") + ")$"
				: "";
		fileNameContainsTextField = new JTextField(fileNameContains, 15);
		addJTextField(advancePanel, fileNameContainsTextField, GuiUtils.font14_un);
		addJLabel(advancePanel, "  文件名不包含字符: ", GuiUtils.font14_cn);
		String fileNameNotContains = notContainsFiletypes.length() > 0 ? "\\.("
				+ notContainsFiletypes.replace(",", "|") + ")$" : "";
		fileNameNotContainsTextField = new JTextField(fileNameNotContains, 15);
		addJTextField(advancePanel, fileNameNotContainsTextField, GuiUtils.font14_un);
		// 是否支持正则
		addJCheckBox(advancePanel, "支持正则", true, GuiUtils.font14_cn, new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				fileNameSupportRegex = ((JCheckBox) event.getSource()).isSelected();
			}
		});
		inputPanel.add(advancePanel);

		add(inputPanel, BorderLayout.NORTH);

		// 探测结果输出
		JPanel detectLogPanel = new JPanel(new BorderLayout());
		detectLogPanel.add(new JScrollPane(resultTextArea));
		add(detectLogPanel, BorderLayout.CENTER);
	}

	/**
	 * append探测文本编码结果.
	 */
	private void appendDetectResult(JTextArea resultTextArea, File file, int detectLength) throws IOException {
		resultTextArea.append(file.getAbsolutePath() + "         Charset: " + detectFileCharset(file, detectLength)
				+ "\n");
	}

	/**
	 * 探测文本编码.
	 */
	public static String detectFileCharset(File file, int detectLength) throws IOException {
		String charset = null;
		FileInputStream fis = null;
		try {
			byte[] buf = new byte[detectLength];
			fis = new FileInputStream(file);
			UniversalDetector detector = new UniversalDetector(null);
			int nread;
			while ((nread = fis.read(buf)) > 0 && !detector.isDone()) {
				detector.handleData(buf, 0, nread);
			}
			detector.dataEnd();
			charset = detector.getDetectedCharset();
			detector.reset();
		} finally {
			if (fis != null) {
				fis.close();
			}
		}
		return charset;
	}

}
